/*
 * Copyright (C) 2012-2013  Romain DUBOIS
 * 
 * This file is part of NeMoS - Network and Modular Software
 * 
 * NeMoS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * NeMoS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with NeMoS.  If not, see <http://www.gnu.org/licenses/>.
 */
package nemos.swing.swixml.customization;

import java.awt.Container;
import java.io.Reader;
import java.util.Locale;

import nemos.resources.IResourcesManager;
import nemos.util.i18n.ITranslator;
import nemos.util.osgi.BundleClassLoader;

import org.jdesktop.application.Application;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.swixml.SwingEngine;
import org.swixml.dom.DOMUtil;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

/**
 * NemosEngine : The NeMoS-specific Swing engine.
 * 
 * <p>
 * Class adapts the SwiXML {@link SwingEngine} into a NeMos/OSGi framework, with
 * classloading and service issues.
 * </p>
 * 
 * @param <T>
 *            The main component type
 * 
 * @author Romain DUBOIS
 */
public class NemosEngine<T extends Container> extends SwingEngine<T> {

    /** The customized localizer */
    private final NemosLocalizer mLocalizer;
    /** The bundle context */
    private final BundleContext mContext;
    /** The main component type */
    private final Class<T> mType;

    /**
     * Constructor
     * 
     * @param pContext
     *            The bundle context
     * @param pType
     *            The main component type
     * @param pTranslator
     *            The translator to use
     */
    public NemosEngine(final BundleContext pContext, final Class<T> pType,
            final ITranslator pTranslator) {
        super();

        mContext = pContext;
        mType = pType;
        mLocalizer = new NemosLocalizer(pTranslator);

        setLocale(Locale.getDefault());
        setResourceBundle(Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME);

        final ServiceReference<?> lRef = pContext.getServiceReference(IResourcesManager.class);
        if (lRef != null) {
            setClassLoader(new BundleClassLoader(lRef.getBundle()));
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.swixml.SwingEngine#render(java.io.Reader)
     */
    @Override
    public T render(final Reader pReader) throws Exception {
        if (pReader == null) {
            throw new IllegalArgumentException();
        }

        return render(DOMUtil.getDocumentBuilder().parse(new InputSource(pReader)));
    }

    /**
     * Parse the DOM document and convert it into component.
     * 
     * @param pDoc
     *            The document to parse
     * @return The described component
     * @throws ClassCastException
     *             If the described component has not the expected type
     * @throws Exception
     *             If an error occurred
     */
    private T render(final Document pDoc) throws Exception {
        getIdMap().clear();

        final NemosParser lParser = new NemosParser(this, mContext);
        return mType.cast(lParser.parse(pDoc, null));
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.swixml.SwingEngine#getLocalizer()
     */
    @Override
    public NemosLocalizer getLocalizer() {
        return mLocalizer;
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.swixml.SwingEngine#setLocale(java.util.Locale)
     */
    @Override
    public void setLocale(final Locale pLocale) {
        super.setLocale(pLocale);

        // For first call, mLocalizer is not initialized
        if (mLocalizer != null) {
            Locale lLocale = pLocale;
            if (SwingEngine.isMacOSXSupported() && Application.getInstance().isMacOSX()) {
                lLocale = new Locale(lLocale.getLanguage(), lLocale.getCountry(),
                        SwingEngine.MAC_OSX_LOCALE_VARIANT);
            }
            mLocalizer.setLocale(lLocale);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.swixml.SwingEngine#setClassLoader(java.lang.ClassLoader)
     */
    @Override
    public void setClassLoader(final ClassLoader pLoader) {
        super.setClassLoader(pLoader);
        mLocalizer.setClassLoader(pLoader);
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.swixml.SwingEngine#setResourceBundle(java.lang.String)
     */
    @Override
    public void setResourceBundle(final String bundlename) {
        mLocalizer.setResourceBundle(bundlename);
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.swixml.SwingEngine#mapMember(java.lang.Object, java.lang.String)
     */
    @SuppressWarnings("unused")
    @Override
    protected void mapMember(final Object widget, final String fieldName) {
        // Map nothing
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.swixml.SwingEngine#mapMember(java.lang.Object, java.lang.String,
     *      java.lang.Class)
     */
    @SuppressWarnings("unused")
    @Override
    protected void mapMember(final Object widget, final String fieldName, final Class<?> cls) {
        // Map nothing
    }
}
